#include "Http_Context.hpp"
#include "Http_Request.hpp"
#include "Http_Response.hpp"
#include <functional>
#include<time.h>
#include<unordered_map>


class HttpServer
{
private:
    using Handler = std::function<void(const HttpRequest &, HttpResponse *)>;

    using Handlers = std::vector<std::pair<std::regex, Handler>>;

    // 不同请求类型的处理方式
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _delete_route;
    std::string _basedir; // 静态根目录

    TcpServer _server;

private:
    void ErrorHandler(const HttpRequest &req, HttpResponse *rsp)
    {
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<hl>";
        body += std::to_string(rsp->_statu);
        body += " ";
        body += Util::StatuDesc(rsp->_statu);
        body += "</h1>";
        body += "</body>";
        body += "</html>";

        rsp->SetContent(body, "text/html");
    }

    // 将HttpResponse中的要素内容按照协议进行组织，发送
    void WriteResponse(const PtrConnection &conn, const HttpRequest &req, HttpResponse &rsp)
    {
        if (req.Close() == true)
        {
            rsp.SetHeader("Connection", "close");
        }
        else
        {
            rsp.SetHeader("Connection", "keep-alive");
        }

        if (rsp._body.empty() == false && rsp.HasHeader("Content-Length") == false)
        {
            rsp.SetHeader("Content-Length", std::to_string(rsp._body.size()));
        }

        if (rsp._body.empty() == false && rsp.HasHeader("Content-Typs") == false)
        {
            rsp.SetHeader("Content-Type", "application/octet-stream");
        }

        if (rsp._redirect_flag == true)
        {
            rsp.SetHeader("Location", rsp._redirect_url);
        }

        // 将rsp中的内容以http的协议格式进行组织

        std::stringstream rsp_str;

        rsp_str << req._version << " " << std::to_string(rsp._statu) << " " << Util::StatuDesc(rsp._statu) << "/r/n";

        for (auto &head : rsp._headers)
        {
            rsp_str << head.first << ": " << head.second << "/r/n";
        }
        rsp_str << "/r/n";
        rsp_str << rsp._body;

        // 发送数据
        conn->Send(rsp_str.str().c_str(), rsp_str.str().size());
    }

    bool IsFileHandler(const HttpRequest &req)
    {
        if (_basedir.empty())
        {
            return false;
        }

        // 请求方法只能是GET或者HEAD
        if (req._method != "GET" && req._method != "HEAD")
        {
            return false;
        }

        // 请求路径有效
        if (Util::ValidPath(req._path) == false)
        {
            return false;
        }

        // 请求的资源必须存在，而且是一个普通文件
        // 有一种特殊的目录：/,/iamge/，这种需要在后面默认追加一个index.html
        // index.html /image/a.png
        // 不要忘了前缀的相对根⽬录,也就是将请求路径转换为实际存在的路径
        // image / a.png->./ wwwroot / image / a.png 
        
        std::string req_path = _basedir + req._path;

        if (req._path.back() == '/')
        {
            req_path += "index.html";
        }
        if (Util::Isregular(req_path) == false)
        {
            return false;
        }
        return true;
    }

    void Dispatcher(HttpRequest &req,HttpResponse *rsp,Handlers &handlers)
    {
        //在对对应的请求路由表中查找，有就调用，没有就返回404状态码
        for(auto &handler :handlers)
        {
            const std::regex &re=handler.first;
            const Handler &functor=handler.second;
            bool ret=std::regex_match(req._path,req._matches,re);
            if(ret==false)
            {
                continue;
            }

            return functor(req,rsp);
        }
        rsp->_statu=404;
    }

    void Route(HttpRequest &req,HttpResponse *rsp)
    {
        //分辨请求的类型是静态资源请求，还是功能性请求

        if(IsFileHandler(req)==true)
        {
            return FileHandler(req,rsp);
        }

        if(req._method=="GET"||req._method=="HEAD")
        {
            return Dispatcher(req,rsp,_get_route);
        }
        else if(req._method=="POST")
        {
            return Dispatcher(req,rsp,_post_route);
        }
        else if(req._method=="PUT")
        {
            return Dispatcher(req,rsp,_put_route);
        }
        else if(req._method=="DELETE")
        {
            return Dispatcher(req,rsp,_delete_route);
        }

        rsp->_statu=405;
        return;
    }

    void OnConnected(const PtrConnection &conn)
    {
        conn->SetContext(HttpContext());
        DBG_LOG("new connection %p",conn.get());
    }


    //缓冲区数据解析和处理
    void OnMessage(const PtrConnection &conn,Buffer* buffer)
    {
        while(buffer->ReadAbleSize()>0)
        {
            HttpContext *context=conn->GetContext()->get<HttpContext>();

            context->RecvHttpRequest(buffer);
            HttpRequest &req=context->Request();
            HttpResponse rsp(context->RespStaut());

            if(context->RespStaut()>=400)
            {
                ErrorHandler(req,&rsp);
                WriteResponse(conn,req,rsp);
                context->RSet();

                buffer->MoveReadOffset(buffer->ReadAbleSize());
                conn->Shutdown();
                return;
            }

            if(context->RecvStaut()!=RECV_HTTP_OVER)
            {
                return;
            }
            Route(req,&rsp);
            WriteResponse(conn,req,rsp);
            context->RSet();

            if(rsp.Close()==true)conn->Shutdown();
        }
        return;
    }

    public:
    HttpServer(int port,int timeout=DEFAL_TUMEOUT):_server(port)
    {
        _server.EnableInactiveRelease(timeout);
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));

    }

    void SetBaseDir(const std::string &path)
    {
        assert(Util::IsDirectory(path)==true);
        _basedir=path;
    }

    void Get(const std::string &pattern,const Handler &handler)
    {
        _get_route.push_back(std::make_pair(std::regex(pattern),handler));
    }

    void Put(const std::string &pattern,const Handler &handler)
    {
        _put_route.push_back(std::make_pair(std::regex(pattern),handler));
    }

    void Delete(const std::string &pattern,const Handler &handler)
    {
        _delete_route.push_back(std::make_pair(std::regex(pattern),handler));
    }

    void SetThreadCount(int count)
    {
        _server.SetThreadCount(count);
    }

    void Listen()
    {
        _server.Start();
    }

};